/**
 * 
 */
package org.swing.utility.input.component;

import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Dimension;

import javax.swing.JComponent;
import javax.swing.JSplitPane;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.SplitPaneUI;
import javax.swing.plaf.basic.BasicSplitPaneUI;

/**
 * @author lqnhu
 *
 */
public class AltFixedSplitPane extends JSplitPane {
	/* BUG_PARADE(DMS): many bugs here */

	/**
	 * Constructor for FixedSplitPane
	 */
	public AltFixedSplitPane() {
	}

	/**
	 * Constructor for FixedSplitPane that has no divider shadow and starts out
	 * with an empty border.
	 */
	public AltFixedSplitPane(boolean visibleDividerBorder) {
		this();
		this.visibleDividerBorder = visibleDividerBorder;
		setBorder(EMPTY_BORDER);
	}

	/**
	 * Constructor for FixedSplitPane
	 */
	public AltFixedSplitPane(int arg0) {
		super(arg0);
	}

	/**
	 * Constructor for FixedSplitPane
	 */
	public AltFixedSplitPane(int arg0, boolean arg1) {
		super(arg0, arg1);
	}

	/**
	 * Constructor for FixedSplitPane
	 */
	public AltFixedSplitPane(int arg0, Component arg1, Component arg2) {
		super(arg0, arg1, arg2);
	}

	/**
	 * Constructor for FixedSplitPane
	 */
	public AltFixedSplitPane(int arg0, boolean arg1, Component arg2,
			Component arg3) {
		super(arg0, arg1, arg2, arg3);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * java.awt.Component#setComponentOrientation(java.awt.ComponentOrientation)
	 */
	@Override
	public void setComponentOrientation(ComponentOrientation o) {
		// Turns out that this is currently ignored by JSplitPane
		// So we are handling it here.
		boolean isLtoR = getComponentOrientation().isLeftToRight();

		// if the layout is stacked/vertical then we are done
		if (getOrientation() == JSplitPane.VERTICAL_SPLIT) {
			return;
		}

		if (o.isLeftToRight() != isLtoR) {
			// Swap the left and right
			Component left = getLeftComponent();
			Component right = getRightComponent();
			setRightComponent(null);
			setLeftComponent(right);
			setRightComponent(left);

			// The resizing is now reversed
			setResizeWeight(isLtoR ? 1 - getResizeWeight() : getResizeWeight());

			// also swap the proportional divider location
			if (hasProportionalLocation) {
				setDividerLocation(isLtoR ? 1 - proportionalLocation
						: proportionalLocation);
			}
		}

		super.setComponentOrientation(o);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JSplitPane#addImpl(java.awt.Component, java.lang.Object,
	 * int)
	 */
	@Override
	protected void addImpl(Component comp, Object constraints, int index) {
		if (comp instanceof JComponent) {
			((JComponent) comp).setPreferredSize(DOT);
		}

		// flip the constraint if we are not left to right
		Object realConstraints = constraints;
		if (!getComponentOrientation().isLeftToRight()) {
			realConstraints = constraints != null
					&& constraints.equals(JSplitPane.RIGHT) ? JSplitPane.LEFT
					: JSplitPane.RIGHT;
		}

		super.addImpl(comp, realConstraints, index);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JSplitPane#setBottomComponent(java.awt.Component)
	 */
	@Override
	public void setBottomComponent(Component comp) {
		if (comp instanceof JComponent) {
			((JComponent) comp).setPreferredSize(DOT);
		}
		super.setBottomComponent(comp);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JSplitPane#setLeftComponent(java.awt.Component)
	 */
	@Override
	public void setLeftComponent(Component comp) {
		if (comp instanceof JComponent) {
			((JComponent) comp).setPreferredSize(DOT);
		}

		if (getComponentOrientation().isLeftToRight()) {
			super.setLeftComponent(comp);
		} else {
			super.setRightComponent(comp);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JSplitPane#setRightComponent(java.awt.Component)
	 */
	@Override
	public void setRightComponent(Component comp) {
		if (comp instanceof JComponent) {
			((JComponent) comp).setPreferredSize(DOT);
		}

		if (getComponentOrientation().isLeftToRight()) {
			super.setRightComponent(comp);
		} else {
			super.setLeftComponent(comp);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JSplitPane#setTopComponent(java.awt.Component)
	 */
	@Override
	public void setTopComponent(Component comp) {
		if (comp instanceof JComponent) {
			((JComponent) comp).setPreferredSize(DOT);
		}
		super.setTopComponent(comp);
	}

	/**
	 * Validates this container and all of its subcomponents. The first time
	 * this method is called, the initial divider position is set.
	 */
	@Override
	public void validate() {
		if (firstValidate) {
			firstValidate = false;
			if (hasProportionalLocation) {
				setDividerLocation(proportionalLocation);
			}
		}
		super.validate();
	}

	/**
	 * Sets the divider location as a percentage of the JSplitPane's size.
	 */
	@Override
	public void setDividerLocation(double newProportionalLoc) {
		double realProportionalLoc = newProportionalLoc;

		// When the orientation is reversed the proportions are reversed.
		if (getComponentOrientation().isLeftToRight()) {
			realProportionalLoc = 1 - realProportionalLoc;
		}

		if (!firstValidate) {
			hasProportionalLocation = true;
			proportionalLocation = realProportionalLoc;
		} else {
			super.setDividerLocation(realProportionalLoc);
		}
	}

	/**
	 * Sets the divider location as a percentage of the JSplitPane's size.
	 */
	@Override
	public void setResizeWeight(double newResizeWeight) {
		double realResizeWeight = newResizeWeight;

		// When the orientation is reversed the proportions are reversed.
		if (getComponentOrientation().isLeftToRight()) {
			realResizeWeight = 1 - realResizeWeight;
		}

		super.setResizeWeight(realResizeWeight);
	}

	/**
	 * Whether visible borders are hinted
	 * 
	 * @return the divider border visiblity hint
	 */
	public boolean isVisibleDividerBorder() {
		return visibleDividerBorder;
	}

	/**
	 * Set a hint whether the border should be visible or not. Look and feels
	 * may ignore this.
	 * 
	 * @param newVisibility
	 */
	public void setVisibleDividerBorder(boolean newVisibility) {
		boolean oldVisibility = isVisibleDividerBorder();
		if (oldVisibility == newVisibility) {
			return;
		}
		visibleDividerBorder = newVisibility;
		firePropertyChange(PROPERTYNAME_VISIBLE_DIVIDER_BORDER, oldVisibility,
				newVisibility);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JSplitPane#updateUI()
	 */
	@Override
	public void updateUI() {
		super.updateUI();
		if (!visibleDividerBorder) {
			SplitPaneUI splitPaneUI = getUI();
			if (splitPaneUI instanceof BasicSplitPaneUI) {
				BasicSplitPaneUI basicUI = (BasicSplitPaneUI) splitPaneUI;
				basicUI.getDivider().setBorder(EMPTY_BORDER);
			}
		}
	}

	private static final Dimension DOT = new Dimension(0, 0);
	private boolean firstValidate = true;
	private boolean hasProportionalLocation;
	private double proportionalLocation;

	/**
	 * Property for border visibility
	 */
	public static final String PROPERTYNAME_VISIBLE_DIVIDER_BORDER = "visibleDividerBorder";

	/**
	 * An Empty Border
	 */
	private static final Border EMPTY_BORDER = new EmptyBorder(0, 0, 0, 0);

	/**
	 * Hint for whether Divider border should be visible.
	 */
	private boolean visibleDividerBorder;

	/**
	 * Serialization ID
	 */
	private static final long serialVersionUID = 3761687909593789241L;
}
